/*
 * Copyright (C) 2017-2021
 * All rights reserved, Designed By
 * Copyright authorization contact 18814114118
 */
package com.shop.cereshop.commons.utils;

import lombok.extern.slf4j.Slf4j;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;

/**
 * 日期工具类
 *
 * @author yuanyao@wistronits.com
 * create on 2019-04-19 17:00
 */
@Slf4j
public class TimeUtils {

    private static final DateTimeFormatter YYYY_MM_DD = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    
    /**
     * 日期时间格式化器：yyyy-MM-dd HH:mm:ss
     */
    public static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

    /**
     * 将指定字符串转换成年月格式  yyyy-MM
     *
     * @return
     */
    public static String setYearMonth(String yearMonth) {
        try {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
            return sdf.format(sdf.parse(yearMonth));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "";
    }

    /**
     * 通过时间秒毫秒数判断两个时间的间隔(天)
     *
     * @param startTime
     * @param endTime
     * @return
     */
    public static int differentDaysByMillisecond(String startTime, String endTime) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date date1 = sdf.parse(startTime);
        Date date2 = sdf.parse(endTime);
        int days = (int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    /**
     * 时间间隔(天)
     *
     * @param time
     * @return
     */
    public static int differentDaysByMillisecond(String time) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date1 = sdf.parse(time);
        long date2 = System.currentTimeMillis();
        int days = (int) ((date2 - date1.getTime()) / (1000 * 3600 * 24));
        return days;
    }

    /**
     * 判断指定时间是否在当前时间之后
     *
     * @param time
     * @return
     */
    public static boolean compareAfterTime(String time) throws Exception {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.parse(time).getTime() >= new Date().getTime();
    }

    /**
     * 获取今天日期  yyyy-MM-dd
     *
     * @return
     */
    public static String today() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.format(new Date());
    }

    /**
     * 获取昨天日期  yyyy-MM-dd
     *
     * @return
     */
    public static String yesterday() {
        Calendar cal = Calendar.getInstance();
        cal.add(Calendar.DATE, -1);
        Date d = cal.getTime();
        SimpleDateFormat sp = new SimpleDateFormat("yyyy-MM-dd");
        String ZUOTIAN = sp.format(d);
        return ZUOTIAN;
    }

    /**
     * 获取今天日期  yyyyMMdd
     *
     * @return
     */
    public static String todayTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        return sdf.format(new Date());
    }

    /**
     * 获取今天日期的时分  HH:mm
     *
     * @return
     */
    public static String hhmm() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
        return sdf.format(new Date());
    }

    /**
     * 获取今天日期的时分秒  HH:mm:ss
     *
     * @return
     */
    public static String hhmmss() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(new Date());
    }

    /**
     * 获取今天日期  yyyy-MM-dd HH:mm:ss
     *
     * @return
     */
    public static String yyMMddHHmmss() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        return sdf.format(new Date());
    }

    public static LocalDateTime parseToLocalDateTime(String time) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        return LocalDateTime.parse(time, formatter);
    }

    /**
     * 判断当前时间是否在某个时间段内
     *
     * @param start
     * @param end
     */
    public static boolean isBelong(String start, String end) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        Date now = null;
        Date beginTime = null;
        Date endTime = null;
        try {
            now = df.parse(df.format(new Date()));
            beginTime = df.parse(start);
            endTime = df.parse(end);
        } catch (Exception e) {
            e.printStackTrace();
        }

        boolean flag = belongCalendar(now, beginTime, endTime);
        return flag;
    }

    /**
     * 判断当前时间是否在时间段内
     *
     * @param nowTime
     * @param beginTime
     * @param endTime
     * @return
     */
    public static boolean belongCalendar(Date nowTime, Date beginTime, Date endTime) {
        Calendar date = Calendar.getInstance();
        date.setTime(nowTime);

        Calendar begin = Calendar.getInstance();
        begin.setTime(beginTime);

        Calendar end = Calendar.getInstance();
        end.setTime(endTime);

        if (date.after(begin) && date.before(end)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 获取次日指定时间
     *
     * @param time
     * @return
     */
    public static String getTomorrow(int time) {
        Calendar cal = Calendar.getInstance();
        cal.setTime(new Date());
        cal.add(Calendar.DAY_OF_YEAR, 1);
        cal.set(Calendar.HOUR_OF_DAY, time);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String dateStr = sdf.format(cal.getTime());
        return dateStr;
    }

    /**
     * 获取当前时间1天后的时间
     *
     * @return
     */
    public static String get24HourAfter() throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());
        calendar.add(Calendar.DATE, 1);
        String date = format.format(calendar.getTime());
        return date;
    }

    /**
     * 获取当前时间指定分钟后的时间
     *
     * @return
     */
    public static String getMinuteAfter(int time) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(new Date());
        calendar.add(Calendar.MINUTE, time);
        String date = format.format(calendar.getTime());
        return date;
    }

    /**
     * 获取指定日期几天后的时间
     */
    public static String getMoreDayAfter(String date, int day) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(format.parse(date));
        calendar.add(Calendar.DATE, day);
        return format.format(calendar.getTime());
    }

    /**
     * 获取指定日期几小时后的时间
     */
    public static String getMoreHourAfter(String date, int hour) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(format.parse(date));
        calendar.add(Calendar.HOUR, hour);
        return format.format(calendar.getTime());
    }

    /**
     * 获取指定日期几年后的时间
     */
    public static String getMoreYearAfter(String date, int year) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(format.parse(date));
        calendar.add(Calendar.YEAR, year);
        return format.format(calendar.getTime());
    }

    /**
     * 比较指定日期是否在今天之前
     */
    public static boolean compareBeforeToday(String time) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        return format.parse(time).getTime() <= new Date().getTime();
    }

    public static String getYearMonth() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
        return format.format(new Date());
    }

    /**
     * 获取指定日期之间的天数
     */
    public static long getBetweenDays(String startTime, String endTime) {
        // 获取日期
        Date date1 = parseDate(startTime, "yyyy-MM-dd");
        Date date2 = parseDate(endTime, "yyyy-MM-dd");

        // 获取相差的天数
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date1);
        long timeInMillis1 = calendar.getTimeInMillis();
        calendar.setTime(date2);
        long timeInMillis2 = calendar.getTimeInMillis();

        long betweenDays = (timeInMillis2 - timeInMillis1) / (1000L * 3600L * 24L);
        return betweenDays;
    }

    /**
     * 将指定的日期字符串转换成日期
     *
     * @param dateStr 日期字符串
     * @param pattern 格式
     * @return 日期对象
     */
    public static Date parseDate(String dateStr, String pattern) {
        SimpleDateFormat sdf = new SimpleDateFormat(pattern);
        Date date;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            throw new RuntimeException("日期转化错误");
        }

        return date;
    }

    /**
     * 将指定的日期字符串转换成默认格式的日期
     *
     * @param dateStr 日期字符串
     * @return 日期对象
     */
    public static Date parseDate(String dateStr) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date;
        try {
            date = sdf.parse(dateStr);
        } catch (ParseException e) {
            throw new RuntimeException("日期转化错误");
        }

        return date;
    }

    /**
     * 获取当月第一天日期MM/dd
     */
    public static String getMonthFirst() {
        // 获取当前年份、月份、日期
        Calendar cale = Calendar.getInstance();
        // 获取当月第一天和最后一天
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String firstday;
        // 获取前月的第一天
        cale = Calendar.getInstance();
        cale.add(Calendar.MONTH, 0);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        firstday = format.format(cale.getTime());
        return firstday;
    }

    /**
     * 获取当月最后一天日期MM/dd
     */
    public static String getMonthLast() {
        // 获取当前年份、月份、日期
        Calendar cale = Calendar.getInstance();
        // 获取当月第一天和最后一天
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        String lastday;
        // 获取前月的最后一天
        cale = Calendar.getInstance();
        cale.add(Calendar.MONTH, 1);
        cale.set(Calendar.DAY_OF_MONTH, 0);
        lastday = format.format(cale.getTime());
        return lastday;
    }

    /**
     * 获取指定年月份当月的每一天日期
     *
     * @param yearParam
     * @param monthParam
     * @return
     */
    public static List<String> getDayByMonth(int yearParam, int monthParam) {
        List list = new ArrayList();
        Calendar aCalendar = Calendar.getInstance(Locale.CHINA);
        aCalendar.set(yearParam, monthParam, 1);
        int year = aCalendar.get(Calendar.YEAR);//年份
        int month = aCalendar.get(Calendar.MONTH);//月份
        int day = aCalendar.getActualMaximum(Calendar.DATE);
        for (int i = 1; i <= day; i++) {
            String aDate = null;
            if (month < 10 && i < 10) {
                aDate = String.valueOf(year) + "-0" + month + "-0" + i;
            }
            if (month < 10 && i >= 10) {
                aDate = String.valueOf(year) + "-0" + month + "-" + i;
            }
            if (month >= 10 && i < 10) {
                aDate = String.valueOf(year) + "-" + month + "-0" + i;
            }
            if (month >= 10 && i >= 10) {
                aDate = String.valueOf(year) + "-" + month + "-" + i;
            }
            list.add(aDate);
        }
        return list;
    }

    /**
     * 根据指定两个时间获取间距时间戳（毫秒级）
     *
     * @param startTime
     * @param endTime
     * @return
     * @throws Exception
     */
    public static Long getCountDownByTime(String startTime, String endTime) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date start = format.parse(startTime);
        Date end = format.parse(endTime);
        Long time = end.getTime() - start.getTime();
        if (time < 1) {
            time = 1L;
        }
        return time;
    }

    /**
     * 比较第一个参数日期是否大于或等于第二个参数日期
     */
    public static boolean compareTo(String startTime, String endTime) throws Exception {
        if (!EmptyUtils.isEmpty(startTime) && !EmptyUtils.isEmpty(endTime)) {
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date bt = format.parse(startTime);
            Date et = format.parse(endTime);
            return bt.after(et) || bt.equals(et);
        }
        return false;
    }

    /**
     * 获取前者时间之后N年的时间
     *
     * @param date
     * @param year
     * @return
     */
    public static String rollYear(String date, int year) throws Exception {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        Date d = format.parse(date);
        Calendar cal = Calendar.getInstance();
        cal.setTime(d);
        cal.add(Calendar.YEAR, year);
        return format.format(cal.getTime());
    }

    /**
     * 获取起始时间范围内的每一天时间
     *
     * @param begintTime
     * @param endTime
     * @return
     */
    public static List<String> findDaysStr(String begintTime, String endTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Date dBegin = null;
        Date dEnd = null;
        try {
            dBegin = sdf.parse(begintTime);
            dEnd = sdf.parse(endTime);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        List<String> daysStrList = new ArrayList<String>();
        daysStrList.add(sdf.format(dBegin));
        Calendar calBegin = Calendar.getInstance();
        calBegin.setTime(dBegin);
        Calendar calEnd = Calendar.getInstance();
        calEnd.setTime(dEnd);
        while (dEnd.after(calBegin.getTime())) {
            calBegin.add(Calendar.DAY_OF_MONTH, 1);
            String dayStr = sdf.format(calBegin.getTime());
            daysStrList.add(dayStr);
        }
        return daysStrList;
    }

    /**
     * 获取当前日期前7天的时间
     *
     * @return
     */
    public static List<String> getRecentSevenDay() {
        String[] arr = new String[7];
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        Calendar c = null;
        for (int i = 0; i < 7; i++) {
            c = Calendar.getInstance();
            c.add(Calendar.DAY_OF_MONTH, -1 * i);
            arr[6 - i] = sdf.format(c.getTime());

        }
        return Arrays.asList(arr);
    }

    /**
     * 取到 hours 以前时间
     *
     * @param hours
     * @return
     */
    public static String headDate(String date, int hours) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Calendar cal = Calendar.getInstance();
        cal.setTime(format.parse(date));
        cal.add(Calendar.HOUR_OF_DAY, -hours);
        return format.format(cal.getTime());
    }

    public static String toRelativeTime(String time) {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date dateTime;
        try {
            dateTime = format.parse(time);
        } catch (ParseException e) {
            log.warn("时间转换异常:" + e.getMessage());
            throw new RuntimeException(e);
        }
        long diff = (System.currentTimeMillis() - dateTime.getTime()) / 1000;

        if (diff < 60) {
            return "刚刚";
        }
        if (diff < 60 * 60) {
            return diff / 60 + "分钟前";
        }
        if (diff < 60 * 60 * 24) {
            return diff / 3600 + "小时前";
        }
        //处理7天内的为天前
        if (diff < 60 * 60 * 24 * 7) {
            return diff / 86400 + "天前";
        }
        return format.format(dateTime);
    }

    /**
     * 将时间戳转换为指定格式的日期字符串
     * @param timestamp 时间戳（毫秒）
     * @param format 日期格式，如 "yyyy-MM-dd HH:mm:ss"
     * @return 格式化后的日期字符串
     */
    public static String timestampToString(long timestamp, String format) {
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date(timestamp));
    }

    /**
     * 将时间戳转换为标准日期时间格式 (yyyy-MM-dd HH:mm:ss)
     * @param timestamp 时间戳（毫秒）
     * @return 格式化后的日期时间字符串
     */
    public static String timestampToString(long timestamp) {
        return timestampToString(timestamp, "yyyy-MM-dd HH:mm:ss");
    }

    /**
     * 将时间戳转换为日期格式 (yyyy-MM-dd)
     * @param timestamp 时间戳（毫秒）
     * @return 格式化后的日期字符串
     */
    public static String timestampToDateString(long timestamp) {
        return timestampToString(timestamp, "yyyy-MM-dd");
    }

    /**
     * 获取 start 到 end 之间所有日期（包含首尾），按正序排列
     *
     * @param start 开始日期，格式 "yyyy-MM-dd"
     * @param end   结束日期，格式 "yyyy-MM-dd"
     * @param ascending 是否按正序排列，true 为正序，false 为倒序
     * @param formatter 日期格式，如 DateTimeFormatter.ofPattern("yyyy-MM-dd")
     * @return 日期字符串列表
     */
    public static List<String> getDateRange(String start, String end, boolean ascending, DateTimeFormatter formatter) {
        LocalDate startDate = LocalDate.parse(start, formatter);
        LocalDate endDate = LocalDate.parse(end, formatter);

        // 确保 startDate <= endDate
        if (startDate.isAfter(endDate)) {
            throw new IllegalArgumentException("开始日期不能晚于结束日期");
        }

        long days = ChronoUnit.DAYS.between(startDate, endDate);

        List<String> result = Stream.iterate(startDate, date -> date.plusDays(1))
                // 包含 endDate
                .limit(days + 1)
                .map(date -> date.format(formatter))
                .collect(Collectors.toList());
        if (!ascending) {
            // 倒序：最新日期在前
            java.util.Collections.reverse(result);
        }
        return result;
    }

    /**
     * 获取 start 到 end 之间所有日期（包含首尾），按正序排列
     *
     * @param start 开始日期，格式 "yyyy-MM-dd"
     * @param end   结束日期，格式 "yyyy-MM-dd"
     * @param ascending 是否按正序排列，true 为正序，false 为倒序
     * @return 日期字符串列表
     */
    public static List<String> getDateRange(String start, String end, boolean ascending) {
        return getDateRange(start, end, ascending, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
    }

    /**
     * 获取 N 天前的日期字符串
     *
     * @param days 天数
     * @return 日期字符串列表
     */
    public static String getNDaysAgo(int days) {
        return LocalDate.now().minusDays(days).format(YYYY_MM_DD);
    }

    /**
     * 从指定日期获取 N 天前
     *
     * @param baseDate 基准日期，格式 "yyyy-MM-dd"
     * @param days 天数
     * @return 日期字符串
     */
    public static String getNDaysAgoFrom(String baseDate, int days) {
        return LocalDate.parse(baseDate, YYYY_MM_DD).minusDays(days).format(YYYY_MM_DD);
    }

    /**
     * 获取 N 天前的 LocalDate 对象
     *
     * @param days 天数
     * @return 日期字符串列表
     */
    public static LocalDate getNDaysAgoDate(int days) {
        return LocalDate.now().minusDays(days);
    }

    /**
     * 获取最近 N 天的日期列表（包含今天）
     *
     * @param n 天数
     * @param ascending 是否按正序排列，true 为正序，false 为倒序
     * @return 日期字符串列表
     */
    public static List<String> getLastNDays(int n, boolean ascending) {
        // 倒序：结果是得到一个从今天开始往前推n天的日期列表，即今天、昨天、前天等
        List<String> result = IntStream.rangeClosed(0, n - 1)
                .mapToObj(i -> LocalDate.now().minusDays(i).format(YYYY_MM_DD))
                .collect(Collectors.toList());
        if (ascending) {
            // 正序：最新日期在前
            java.util.Collections.reverse(result);
        }
        return result;
    }

    //    将localDateTime转换成时间戳的形式
    public  static Long localDateTimeToTimestamp(LocalDateTime localDateTime) {
        return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
    }

    //    将String转换成localDateTime
    public  static LocalDateTime stringToLocalDateTime(String date) {
        return LocalDateTime.parse(date);
    }

    //    将时间戳转换成localDateTime
    public static LocalDateTime timestampToLocalDateTime(Long timestamp) {
        return LocalDateTime.ofInstant(java.time.Instant.ofEpochMilli(timestamp), ZoneId.systemDefault());
    }

    public static void main(String[] args) {
        List<String> dates = getDateRange("2025-09-10", "2025-09-18", true, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        dates.forEach(System.out::println);
    }

    public static Date StringToDate(String paymentTime) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        try {
            return sdf.parse(paymentTime);
        } catch (ParseException e) {
            throw new RuntimeException("日期转化错误: " + paymentTime, e);
        }
    }
}
